/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef NCI_CONFIG_MANAGER_DISABLE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "nfc_osi_api.h"
#include "nfc_config_api.h"
#include "nfc_debug_api.h"
#include "nfc_transport_api.h"
#include "osi_config_parser.h"
#include "osi_config_defs.h"
/**
 * @file config_manager.c
 * @brief NFC协议栈配置管理模块API实现
 */

/**
 * @brief NCI配置文件(tmsnci.conf)路径数组
 * @note 通过NFC_CONFIG_PATHS宏定义配置文件搜索路径列表
 */
static const char *s_cf_path[] = NFC_CONFIG_PATHS("tmsnci.conf");

/**
 * @brief NCI配置文件(tmsnci.conf)路径数组大小
 */
static const size_t s_cf_path_num = OSI_ARRAY_SIZE(s_cf_path);

/**
 * @brief NCI配置初始化状态标志
 * @note true: 配置已初始化完成
 *       false: 配置未初始化
 */
static bool s_is_inited = false;

/**
 * @brief 配置管理器互斥锁
 * @note 用于保护配置数据的并发访问
 */
tMUTEX s_cf_lock = {
    .name = "s_cf_lock",
    .state = MUTEX_STATE_STATIC,
    .is_recursive = false,
    .mutex = PTHREAD_MUTEX_INITIALIZER,
    .cond = PTHREAD_COND_INITIALIZER,
};

/**
 * @brief NFC配置管理器实例
 * @note 用于管理NCI协议栈配置参数、Vendor配置参数等
 *       包含配置参数表和配置参数值
 */
static tNFC_CONFIG_MANAGER s_cm = {0};

/**
 * @brief NCI协议栈基础配置参数表
 *
 * 本表用于存储从tmsnci.conf文件中解析的NCI协议栈基础配置参数。每个参数项包含:
 * - 参数名称
 * - 对应的配置结构体成员地址
 * - 默认值(可选)
 *
 * 支持解析的ITEM类型定义在osi_config_parser.h中
 *
 * @note 参数项默认值配置规则:
 *       1. 表中参数项均不配置默认值
 *       2. 表中参数项部分配置默认值
 *       3. 表中参数项均配置默认值
 *       2、3需配合使用osi_config_set_defaults接口进行默认值处理
 *       eg:
 *       配置默认值: UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level, 0x03)
 *       不配置默认值: UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level)
 */
static tNFC_CF_PARAM s_cf_table[] = {
    UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level, 0x03),
    UINT8_ITEM(POLLING_TECH_MASK, &s_cm.cf.polling_tech_mask, 0xFF),
    UINT32_ITEM(NCI_RSP_TIMEOUT, &s_cm.cf.nci_rsp_timeout, 2000),
    UINT32_ITEM(NCI_NTF_TIMEOUT, &s_cm.cf.nci_ntf_timeout, 2000),
    UINT32_ITEM(NCI_DATA_TIMEOUT, &s_cm.cf.nci_data_timeout, 2000),
    UINT32_ITEM(RW_ACTIVATE_TIMEOUT, &s_cm.cf.rw_activate_timeout, 2000),
    UINT8_ITEM(DEFAULT_AID_PWR_STATE, &s_cm.cf.aid_pwr, 0x3B),
    UINT16_ITEM(DEFAULT_SYS_CODE, &s_cm.cf.sys_code, 0xFEFE),
    UINT8_ITEM(AID_MATCHING_MODE, &s_cm.cf.aid_match_mode, 0x03),
    UINT8_ITEM(TMS_LX_DEBUG_LEVEL, &s_cm.cf.tms_lx_debug_level, 0),
    UINT32_ITEM(MAX_RAPDU_WAIT_TIME, &s_cm.cf.max_rapdu_wait_time, 30000),
    BOOL_ITEM(T5T_MUTE_LEGACY, &s_cm.cf.t5t_mute_legacy, false),
};

/**
 * @brief NCI协议栈Vendor配置参数表
 *
 * 本表用于存储从Vendor配置文件(libnfc-tms.conf)获取的可配置参数。每个参数项包含:
 * - 参数名称
 * - 对应的配置结构体成员地址
 * - 默认值(可选)
 *
 * 支持解析的ITEM类型定义在osi_config_parser.h中
 *
 * @note 参数项默认值配置规则:
 *       1. 表中参数项均不配置默认值
 *       2. 表中参数项部分配置默认值
 *       3. 表中参数项均配置默认值
 *       2、3需配合使用osi_config_set_defaults接口进行默认值处理
 *       eg:
 *       配置默认值: UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level, 0x03)
 *       不配置默认值: UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level)
 */
static tNFC_CF_PARAM s_vnd_cf_table[] = {
    BOOL_ITEM(NFA_POLL_BAIL_OUT_MODE, &s_cm.cf.vendor_cf.nfa_poll_bailout_mode, false),
    UINT8_ITEM(DEFAULT_OFFHOST_ROUTE, &s_cm.cf.vendor_cf.offhost_route, 0xC0),
    UINT8_ITEM(DEFAULT_NFCF_ROUTE, &s_cm.cf.vendor_cf.offhost_route_felica, 0x00),
    UINT8_ITEM(DEFAULT_SYS_CODE_ROUTE, &s_cm.cf.vendor_cf.system_code_route, 0x00),
    UINT8_ITEM(DEFAULT_SYS_CODE_PWR_STATE, &s_cm.cf.vendor_cf.system_code_power_state, 0x11),
    UINT8_ITEM(DEFAULT_ROUTE, &s_cm.cf.vendor_cf.aid_route, 0xC0),
    UINT8_ITEM(OFF_HOST_ESE_PIPE_ID, &s_cm.cf.vendor_cf.offhost_ese_pipe_id, 0),
    UINT8_ITEM(OFF_HOST_SIM_PIPE_ID, &s_cm.cf.vendor_cf.offhost_sim_pipe_id, 0),
    UINT32_ITEM(ISO_DEP_MAX_TRANSCEIVE, &s_cm.cf.vendor_cf.max_iso_dep_transceive_length, 0),
    ARRAY_ITEM(DEVICE_HOST_WHITE_LIST, &s_cm.cf.vendor_cf.host_allow_list, "{C0, 80, 81}"),
    ARRAY_ITEM(OFFHOST_ROUTE_UICC, &s_cm.cf.vendor_cf.offhost_route_uicc, "{0x80, 0x81}"),
    ARRAY_ITEM(OFFHOST_ROUTE_ESE, &s_cm.cf.vendor_cf.offhost_route_ese, "{0xC0}"),
    UINT8_ITEM(DEFAULT_ISODEP_ROUTE, &s_cm.cf.vendor_cf.iso_dep_route, 0xC0),
};

/**
 * @brief NCI协议栈Vendor扩展配置参数表
 *
 * 本表用于存储从Vendor配置文件(libnfc-tms.conf)获取的扩展可配置参数。每个参数项包含:
 * - 参数名称
 * - 对应的配置结构体成员地址
 * - 默认值(可选)
 *
 * 支持解析的ITEM类型定义在osi_config_parser.h中
 *
 * @note 参数项默认值配置规则:
 *       1. 表中参数项均不配置默认值
 *       2. 表中参数项部分配置默认值
 *       3. 表中参数项均配置默认值
 *       2、3需配合使用osi_parse_defaults接口进行默认值处理
 *       eg:
 *       配置默认值: UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level, 0x03)
 *       不配置默认值: UINT8_ITEM(NCI_LOG_LEVEL, &s_cm.cf.nci_log_level)
 */
static tNFC_CF_PARAM s_vnd_ext_cf_table[] = {
    UINT16_ITEM(TMS_MAX_APDU_WAIT_TIME, &s_cm.cf.vendor_cf.max_apdu_wait_time, 0),
    UINT8_ITEM(TMS_NFCEE_PL_CFG, &s_cm.cf.vendor_cf.nfcee_pl_cfg, 0),
    UINT8_ITEM(TMS_NFCEE_PL_VALUE, &s_cm.cf.vendor_cf.nfcee_pl_value, 0),
    UINT8_ITEM(DEFAULT_T4TNFCEE_AID_POWER_STATE, &s_cm.cf.vendor_cf.t4t_nfcee_aid_power_state, 0x3B),
    UINT8_ITEM(TMS_T4T_NFCEE_ENABLE, &s_cm.cf.vendor_cf.t4t_nfcee_enable, 0x00),
    UINT8_ITEM(TMS_SET_ALL_ROUTE_DEFAULT, &s_cm.cf.vendor_cf.set_all_route_default, 0x01),
    UINT8_ITEM(TMS_DEFAULT_HCE_TECH, &s_cm.cf.vendor_cf.default_hce_tech, 0x03),
    UINT8_ITEM(HOST_LISTEN_TECH_MASK, &s_cm.cf.vendor_cf.host_listen_tech_mask, 0xFF),
    ARRAY_ITEM(TMS_FORUM_DISABLE, &s_cm.cf.vendor_cf.tms_forum_disable, "{20, 02, 05, 01, A0, 44, 01, 01}"),
};

/**
 * @brief 检查NCI配置是否已初始化
 *
 * 检查NCI配置是否已经初始化。如果未初始化，将执行以下步骤：
 * 1. 初始化配置管理结构体
 * 2. 设置默认配置值
 * 3. 加载并解析配置文件
 * 4. 获取厂商特定配置
 *
 * @note 此函数主要在内部使用，由需要访问配置的公共函数调用。
 *       它不负责加锁，调用者应确保线程安全。
 *       如果初始化失败，将释放已分配的资源。
 *
 * @param[in] result 指向uint32_t的指针，用于接收配置文件解析的结果代码。
 *                   result包含两部分信息：
 *                   - 低16位：解析失败的行号
 *                   - 高16位：解析失败的项数
 *
 * @return 如果配置已初始化或成功初始化，则返回true；否则返回false。
 */
static bool is_initialized(uint32_t *result)
{
    if (s_is_inited) {
        return true;
    }

    NFCLOG_I("Not initialized, attempting to initialize...");

    /* 初始化配置管理结构体 */
    s_cm.cf_table = s_cf_table;
    s_cm.cf_table_len = OSI_ARRAY_SIZE(s_cf_table);
    s_cm.vnd_cf_table = s_vnd_cf_table;
    s_cm.vnd_cf_table_len = OSI_ARRAY_SIZE(s_vnd_cf_table);
    s_cm.vnd_ext_cf_table = s_vnd_ext_cf_table;
    s_cm.vnd_ext_cf_table_len = OSI_ARRAY_SIZE(s_vnd_ext_cf_table);

    /* 设置默认配置值 */
    if (!osi_config_set_defaults(s_cm.cf_table, s_cm.cf_table_len)) {
        NFCLOG_E("Failed to set default values");
        goto free_cf_table;
    }

    if (!osi_config_set_defaults(s_cm.vnd_cf_table, s_cm.vnd_cf_table_len)) {
        NFCLOG_E("Failed to set vnd default values");
        goto free_vnd_cf_table;
    }

    if (!osi_config_set_defaults(s_cm.vnd_ext_cf_table, s_cm.vnd_ext_cf_table_len)) {
        NFCLOG_E("Failed to set vnd ext default values");
        goto free_all_cf_table;
    }

    /* 查找并加载配置文件 */
    const char *path_name = osi_config_file_find(s_cf_path, s_cf_path_num);
    if (!path_name) {
        NFCLOG_E("NCI config file not found");
        goto free_all_cf_table;
    }

    NFCLOG_D("Found config path: %s", path_name);

    /* 解析配置文件 */
    *result = osi_config_parse(path_name, s_cm.cf_table, s_cm.cf_table_len);
    if (nfc_cf_get_err_sum(*result) != 0 || nfc_cf_get_err_line(*result) == 0xFFFF) {
        NFCLOG_E("Failed to parse %s, err sum: %u, parse line: %u",
                 path_name, nfc_cf_get_err_sum(*result), nfc_cf_get_err_line(*result));
        goto free_all_cf_table;
    }

    /* 获取厂商特定配置 */
    if (tp_get_config(&s_cm) != NFC_STATUS_OK) {
        NFCLOG_E("Failed to get vendor config");
        goto free_all_cf_table;
    }

    s_is_inited = true;
    NFCLOG_D("Initialized");
    return true;

free_all_cf_table:
    osi_config_unparse(s_cm.vnd_ext_cf_table, s_cm.vnd_ext_cf_table_len);
free_vnd_cf_table:
    osi_config_unparse(s_cm.vnd_cf_table, s_cm.vnd_cf_table_len);
free_cf_table:
    osi_config_unparse(s_cm.cf_table, s_cm.cf_table_len);
    return false;
}

/**
 * @brief 获取NFC配置对象
 *
 * 获取NFC协议栈配置对象，如果配置未初始化则尝试初始化。
 * 如果初始化失败则终止程序执行。
 *
 * @note 本函数是线程安全的，使用互斥锁保护配置数据的访问
 * @note 如果互斥锁操作失败，会记录错误日志但继续执行
 *
 * @return 返回指向NFC配置对象的指针
 * @retval &s_cm.cf 成功获取配置对象
 * @retval NULL 不会返回NULL，获取失败时直接终止程序
 */
const tNFC_CF *nfc_config_get(void)
{
    uint32_t result = 0;

    NFCLOG_D("Enter");
    if (osi_mutex_lock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex lock failed!!!");
    }

    if (!is_initialized(&result)) {
        NFCLOG_E("Failed to get config. Aborting");
        exit(0);
    }

    if (osi_mutex_unlock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex unlock failed!!!");
    }
    return &s_cm.cf;
}

/**
 * @brief 重置NFC配置状态
 *
 * 重置NFC协议栈配置状态，将其标记为未加载状态。
 * 释放所有已加载的配置数据，包括基础配置、厂商配置和扩展配置。
 * 下次调用nfc_config_get()时会重新加载配置。
 *
 * @note 本函数是线程安全的，使用互斥锁保护配置数据的访问
 * @note 如果互斥锁操作失败，会记录错误日志但继续执行
 */
void nfc_config_reset(void)
{
    if (osi_mutex_lock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex lock failed!!!");
    }
    osi_config_unparse(s_cm.vnd_ext_cf_table, s_cm.vnd_ext_cf_table_len);
    osi_config_unparse(s_cm.vnd_cf_table, s_cm.vnd_cf_table_len);
    osi_config_unparse(s_cm.cf_table, s_cm.cf_table_len);
    s_is_inited = false;

    if (osi_mutex_unlock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex unlock failed!!!");
    }
    NFCLOG_D("Reset complete");
}

/**
 * @brief 获取NFC配置对象(调试版本)
 *
 * 获取NFC协议栈配置对象，如果配置未初始化则尝试初始化。
 * 与nfc_config_get()不同，本函数在初始化失败时返回NULL而不是终止程序。
 * 主要用于调试场景，可以获取配置解析失败的具体信息。
 *
 * @note 本函数是线程安全的，使用互斥锁保护配置数据的访问
 * @note 如果互斥锁操作失败，会记录错误日志但继续执行
 *
 * @param[out] result 指向uint32_t的指针，用于接收配置文件解析的结果代码。
 *                   result包含两部分信息：
 *                   - 低16位：解析失败的行号
 *                   - 高16位：解析失败的项数
 *
 * @return 返回指向NFC配置对象的指针
 * @retval &s_cm.cf 成功获取配置对象
 * @retval NULL 配置初始化失败
 */
const tNFC_CF *nfc_config_get_debug(uint32_t *result)
{
    NFCLOG_D("Enter");
    if (osi_mutex_lock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex lock failed!!!");
    }

    if (!is_initialized(result)) {
        if (osi_mutex_unlock(&s_cf_lock) != NFC_STATUS_OK) {
            NFCLOG_E("Mutex unlock failed!!!");
        }
        return NULL;
    }

    if (osi_mutex_unlock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex unlock failed!!!");
    }
    return &s_cm.cf;
}

/**
 * @brief 检查指定的键值是否存在于配置中，并返回对应的值
 *
 * 本函数用于在NFC配置系统中查找指定键对应的配置项值。函数会依次在以下三个配置表中查找:
 * 1. 基础配置表(s_cm.cf_table)
 * 2. Vendor配置表(s_cm.vnd_cf_table)
 * 3. Vendor扩展配置表(s_cm.vnd_ext_cf_table)
 *
 * @note 本函数是线程安全的，使用互斥锁保护配置数据的访问
 * @note 如果互斥锁操作失败，会记录错误日志但继续执行
 * @note 如果配置未初始化，则先初始化配置，若初始化失败，函数会终止程序执行
 *
 * @param[in] key 配置项的键，用于在配置列表中查找对应的配置项
 * @param[out] pp_value 返回指向键对应配置项值的指针。如果未找到配置项，该指针不会被修改
 * @param[out] value_size 返回键对应配置项值大小的指针。如果未找到配置项，该指针不会被修改
 *
 * @return 如果成功找到配置项并获取其值，则返回true；否则返回false
 */
bool nfa_config_get_value_present(const tCF_KEY key, const void **pp_value, size_t *value_size)
{
    OSI_CHK_PARAM_INVALID(!key, return false);
    uint32_t result = 0;

    if (osi_mutex_lock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex lock failed!!!");
    }

    if (!is_initialized(&result)) {
        NFCLOG_E("Get config failed while checking key '%s'. Aborting", key);
        if (osi_mutex_unlock(&s_cf_lock) != NFC_STATUS_OK) {
            NFCLOG_E("Mutex unlock failed!!!");
        }
        exit(0);
    }

    bool found = osi_config_get_value_present(s_cm.cf_table, s_cm.cf_table_len, key, pp_value, value_size);
    if (!found) {
        found = osi_config_get_value_present(s_cm.vnd_cf_table, s_cm.vnd_cf_table_len, key, pp_value, value_size);
        if (!found) {
            found = osi_config_get_value_present(s_cm.vnd_ext_cf_table, s_cm.vnd_ext_cf_table_len,
                                                 key, pp_value, value_size);
        }
    }

    if (osi_mutex_unlock(&s_cf_lock) != NFC_STATUS_OK) {
        NFCLOG_E("Mutex unlock failed!!!");
    }
    return found;
}
#endif /* NCI_CONFIG_MANAGER_DISABLE */